<!doctype html>
<html lang="zh-cn">
<head>

    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.57.2" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>WayToGo | The Sky of OtsWang</title>
    <meta property="og:title" content="WayToGo - The Sky of OtsWang">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content="2018-11-27T11:22:24&#43;08:00">
        
        
    <meta property="article:modified_time" content="2019-01-29T15:42:06&#43;08:00">
        
    <meta name="Keywords" content="golang,go语言,otswang,java,博客,python">
    <meta name="description" content="学习Go语言的成长之路">
        
    <meta name="author" content="OtsWang">
    <meta property="og:url" content="https://otswang.gitee.io/hugo/post/go/way_to_go/">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

    <link rel="stylesheet" href="/hugo/css/normalize.css">
    
        <link rel="stylesheet" href="/hugo/css/prism.css">
    
    <link rel="stylesheet" href="/hugo/css/style.css">
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>

    


    
    
</head>

<body>
<header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://otswang.gitee.io/hugo/">
                        The Sky of OtsWang
                    </a>
                
                <p class="description">擅长写HelloWorld的小小码农</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    
                    
                    <a  href="https://otswang.gitee.io/hugo/" title="Home">Home</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/tags/" title="Tags">Tags</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/categories/" title="Categories">Categories</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/archives/" title="Archives">Archives</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/about/" title="About">About</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>


<div id="body">
    <div class="container">
        <div class="col-group">

            <div class="col-8" id="main">
                <div class="res-cons">
                    <article class="post">
                        <header>
                            <h1 class="post-title">WayToGo</h1>
                        </header>
                        <date class="post-meta meta-date">
                            2018年11月27日
                        </date>
                        
                        <div class="post-meta">
                            <span>|</span>
                            
                                <span class="meta-category"><a href="https://otswang.gitee.io/hugo/categories/go">Go</a></span>
                            
                        </div>
                        
                        
                        
                        <div class="post-content">
                            <p>学习go语言的成长之路。</p>

<h2 id="go-哲学">Go 哲学</h2>

<ul>
<li>没有不必要的代码：不必要的import会造成编译器报错。</li>
<li>干净、可读的代码和简洁性是Go 追求的主要目标。</li>
<li>Go语言集众多编程范式之所长，并以自己独到的方式将它们融合在一起。程序员们可以用他们喜欢的风格去设计程序。</li>
<li>相对于设计规则上的灵活，Go语言有着明确且近乎严格的编码规范。我们可以通过“go fmt”命令来按照官方的规范格式化代码。</li>
<li>Go语言是强调软件工程的编程语言。它自带了非常丰富的标准命令，涵盖了软件生命周期（开发、测试、部署、维护等等）的各个环节。</li>
<li>Go语言是云计算时代的编程语言。它关注高并发程序，并旨在开发效率和运行效率上取得平衡。</li>
<li>Go语言提倡交换数据，而不是共享数据。它的并发原语Goroutine和Channel是其中的两大并发编程利器。同时，Go语言也提供了丰富的同步工具，以供程序员们根据场景选用。然而，后者就不属于语言级别的支持了。</li>
</ul>

<h2 id="概览">概览</h2>

<p>主要关键字(25个):</p>

<table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>

<tbody>
<tr>
<td>break</td>
<td>default</td>
<td>func</td>
<td>interface</td>
<td>select</td>
</tr>

<tr>
<td>case</td>
<td>defer</td>
<td>go</td>
<td>map</td>
<td>struct</td>
</tr>

<tr>
<td>chan</td>
<td>else</td>
<td>goto</td>
<td>package</td>
<td>switch</td>
</tr>

<tr>
<td>const</td>
<td>fallthrough</td>
<td>if</td>
<td>range</td>
<td>type</td>
</tr>

<tr>
<td>continue</td>
<td>for</td>
<td>import</td>
<td>return</td>
<td>var</td>
</tr>
</tbody>
</table>

<ul>
<li>var和const 变量和常量申明</li>
<li>package和import 包概念</li>
<li>func 用于定义函数和方法</li>
<li>return 用于从函数返回</li>
<li>defer 用于类似析构函数</li>
<li>go 用于并发</li>
<li>select 用于选择不同类型的通讯</li>
<li>interface 用于定义接口</li>
<li>struct 用于定义抽象数据类型</li>
<li>break、case、continue、for、fallthrough、else、if、switch、goto、default用于流程控制</li>
<li>chan用于channel通讯</li>
<li>type用于声明自定义类型</li>
<li>map用于声明map类型数据</li>
<li>range用于读取slice、map、channel数据</li>
</ul>

<h2 id="数据类型">数据类型</h2>

<p>Go 拥有各值类型，包括字符串，整形，浮点型，布尔型等。
每个值都必须在经过编译后属于某个类型（编译器必须能够推断出所有值的类型），因为 Go 语言是一种静态类型语言。</p>

<table>
<thead>
<tr>
<th>类型</th>
<th>说明</th>
</tr>
</thead>

<tbody>
<tr>
<td>布尔类型</td>
<td>由两个预定义常量组成： <code>flase</code>与<code>true</code></td>
</tr>

<tr>
<td>数字类型</td>
<td>算术类型，包括：整数类型和浮点值</td>
</tr>

<tr>
<td>字符串类型</td>
<td>不可变的类型，一旦创建，不可更改内容，预先声明的字符串类型为<code>string</code></td>
</tr>

<tr>
<td>派生类型</td>
<td>包括：指针类型，数组类型，结构类型，聚合类型，函数类型，切片类型，函数类型，接口类型等</td>
</tr>
</tbody>
</table>

<p><strong>数值类型</strong></p>

<p><strong>整型</strong> :int 和 uint 两种类型。默认的位数由操作系统确定。</p>

<p>衍生类型：</p>

<table>
<thead>
<tr>
<th>int</th>
<th>uint</th>
<th>alias</th>
</tr>
</thead>

<tbody>
<tr>
<td>int8</td>
<td><strong>uint8</strong></td>
<td>byte</td>
</tr>

<tr>
<td>int16</td>
<td>uint16</td>
<td></td>
</tr>

<tr>
<td><strong>int32</strong></td>
<td>uint32</td>
<td>rune</td>
</tr>

<tr>
<td>int64</td>
<td>uint64</td>
<td></td>
</tr>
</tbody>
</table>

<p><strong>浮点型</strong> :float32和float64 两种类型。</p>

<p><strong>复数</strong> : complex64 和 complex128</p>

<pre><code class="language-go">var test1 complex64 = 3+4i
</code></pre>

<h2 id="可见性">可见性</h2>

<p>强制使用首字母大写表示外部可见，类似于Java的public，小写字母表示包内可见，类似于Java的privated。</p>

<h2 id="定义变量">定义变量</h2>

<p>使用<code>var</code>关键字是Go最基本的定义变量方式，与C语言不同的是Go把变量类型放在变量名后面。</p>

<ul>
<li><p>简化1 同时可以定义多个变量：</p>

<pre><code class="language-go">var name, city, country string
var age, count, num int = 1,2,3
</code></pre></li>

<li><p>简化2 推断type</p>

<pre><code class="language-go">var age, count, num = 1,2,3
</code></pre></li>

<li><p>简化3 省略<code>var</code></p>

<pre><code class="language-go">age, count, num := 1,2,3
</code></pre></li>
</ul>

<blockquote>
<p>省略<code>var</code>和<code>type</code>的方式称为<strong>简短声明</strong>，但其限制为只能在函数内部使用，因此一般使用<code>var</code>声明全局变量。</p>
</blockquote>

<h2 id="语法规则">语法规则</h2>

<p>gv中是不需要添加<code>;</code>的，编译器会自动添加。这也导致<code>{}</code>需要在首行末尾开始。</p>

<pre><code class="language-go">func test() { // 不能另起一行
  // ...
}
</code></pre>

<h2 id="go的包-package">Go的包 package</h2>

<p>包是根据<code>package &lt;packageName&gt;</code>来确定的，与文件夹的名称无关。</p>

<h2 id="go的-make-与-new">Go的 make 与 new</h2>

<p><code>make</code>用于内建类型（<code>map</code>、<code>slice</code> 和<code>channel</code>）的内存分配。<code>new</code>用于各种类型的内存分配。</p>

<p>内建函数<code>new</code>本质上说跟其它语言中的同名函数功能一样：<code>new(T)</code>分配了零值填充的<code>T</code>类型的内存空间，并且返回其地址，即一个<code>*T</code>类型的值。用Go的术语说，它返回了一个指针，指向新分配的类型<code>T</code>的零值。这一点非常重要：</p>

<blockquote>
<p><code>new</code>返回指针。</p>
</blockquote>

<p>内建函数<code>make(T, args)</code>与<code>new(T)</code>有着不同的功能，make只能创建<code>slice</code>、<code>map</code>和<code>channel</code>，并且返回一个有初始值(非零)的<code>T</code>类型，而不是<code>*T</code>。本质来讲，导致这三个类型有所不同的原因是指向数据结构的引用在使用前必须被初始化。例如，一个<code>slice</code>，是一个包含指向数据（内部<code>array</code>）的指针、长度和容量的三项描述符；在这些项目被初始化之前，<code>slice</code>为<code>nil</code>。对于<code>slice</code>、<code>map</code>和<code>channel</code>来说，<code>make</code>初始化了内部的数据结构，填充适当的值。</p>

<blockquote>
<p><code>make</code>返回初始化后的（非零）值。</p>
</blockquote>

<p>go 的 零值</p>

<pre><code class="language-go">int     0
int8    0
int32   0
int64   0
uint    0x0
rune    0 //rune的实际类型是 int32
byte    0x0 // byte的实际类型是 uint8
float32 0 //长度为 4 byte
float64 0 //长度为 8 byte
bool    false
string  &quot;&quot;
</code></pre>

<h2 id="panic和recover">Panic和Recover</h2>

<p>Go没有像Java那样的异常机制，它不能抛出异常，而是使用了<code>panic</code>和<code>recover</code>机制。一定要记住，这是个强大的工具，但请明智谨慎地使用它。</p>

<p>Panic</p>

<blockquote>
<p>是一个内建函数，可以中断原有的控制流程，进入一个<code>panic</code>状态中。当函数<code>F</code>调用<code>panic</code>，函数F的执行被中断，但是<code>F</code>中的延迟函数(defer)会正常执行，然后F返回到调用它的地方。在调用的地方，<code>F</code>的行为就像调用了<code>panic</code>。这一过程继续向上，直到发生<code>panic</code>的<code>goroutine</code>中所有调用的函数返回，此时程序退出。<code>panic</code>可以直接调用<code>panic</code>产生。也可以由运行时错误产生，例如访问越界的数组。</p>
</blockquote>

<p>Recover</p>

<blockquote>
<p>是一个内建的函数，可以让进入<code>panic</code>状态的<code>goroutine</code>恢复过来。<code>recover</code>仅在延迟函数中有效。在正常的执行过程中，调用<code>recover</code>会返回<code>nil</code>，并且没有其它任何效果。如果当前的<code>goroutine</code>陷入<code>panic</code>状态，调用<code>recover</code>可以捕获到<code>panic</code>的输入值，并且恢复正常的执行。</p>
</blockquote>

<h2 id="main-函数和-init-函数"><code>main</code>函数和<code>init</code>函数</h2>

<p>Go里面有两个保留的函数：<code>init</code>函数（能够应用于所有的<code>package</code>）和<code>main</code>函数（只能应用于<code>package main</code>）。这两个函数在定义时不能有任何的参数和返回值。虽然一个<code>package</code>里面可以写任意多个<code>init</code>函数，但这无论是对于可读性还是以后的可维护性来说，我们都强烈建议用户在一个<code>package</code>中每个文件只写一个<code>init</code>函数。</p>

<p>Go程序会自动调用<code>init()</code>和<code>main()</code>，所以你不需要在任何地方调用这两个函数。每个<code>package</code>中的<code>init</code>函数都是可选的，但<code>package main</code>就必须包含一个<code>main</code>函数。</p>

<p>程序的初始化和执行都起始于<code>main</code>包。如果<code>main</code>包还导入了其它的包，那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入，那么它只会被导入一次（例如很多包可能都会用到<code>fmt</code>包，但它只会被导入一次，因为没有必要导入多次）。当一个包被导入时，如果该包还导入了其它的包，那么会先将其它包导入进来，然后再对这些包中的包级常量和变量进行初始化，接着执行<code>init</code>函数（如果有的话），依次类推。等所有被导入的包都加载完毕了，就会开始对<code>main</code>包中的包级常量和变量进行初始化，然后执行<code>main</code>包中的<code>init</code>函数（如果存在的话），最后执行<code>main</code>函数。下图详细地解释了整个执行过程：</p>

<p><img src="/hugo/src/img/go/init_2.png" /></p>

<h2 id="method">method</h2>

<p>通过<code>method</code>来实现对象的作用.</p>

<p><code>method</code>是附属在一个给定的类型上的，他的语法和函数的声明语法几乎一样，只是在<code>func</code>后面增加了一个receiver(也就是method所依从的主体)。</p>

<blockquote>
<p>&ldquo;A method is a function with an implicit first argument, called a receiver.&rdquo;</p>
</blockquote>

<p>method的语法如下：</p>

<pre><code class="language-go">	func (r ReceiverType) funcName(parameters) (results)
</code></pre>

<p>在使用method的时候重要注意几点</p>

<ul>
<li>虽然method的名字一模一样，但是如果接收者不一样，那么method就不一样</li>
<li>method里面可以访问接收者的字段</li>
<li>调用method通过<code>.</code>访问，就像struct里面访问字段一样</li>
</ul>

<blockquote>
<p>如果一个method的receiver是*T,你可以在一个T类型的实例变量V上面调用这个method，而不需要&amp;V去调用这个method</p>
</blockquote>

<p>类似的</p>

<blockquote>
<p>如果一个method的receiver是T，你可以在一个*T类型的变量P上面调用这个method，而不需要 *P去调用这个method</p>
</blockquote>

<h2 id="interface">interface</h2>

<p>简单的说，interface是一组method签名的组合，我们通过interface来定义对象的一组行为。
如果某个对象实现了某个接口的所有方法，则此对象就实现了此接口。</p>

<p>任意的类型都实现了空interface(我们这样定义：interface{})，也就是包含0个method的interface。</p>

<pre><code class="language-go">package main

import &quot;fmt&quot;

type Human struct {
	name string
	age int
	phone string
}

type Student struct {
	Human  // 匿名字段
	school string
	loan float32
}

type Employee struct {
	Human
	company string
	money float32
}

type Men interface {
	SayHi()
	Sing(lyrics string)
}

func (h Human) SayHi()  {
	fmt.Printf(&quot;Hi, I am %s you can call me on %s\n&quot;, h.name, h.phone)
}

func (h Human) Sing(lyrics string) {
	fmt.Println(&quot;la la la la ... &quot;, lyrics)
}

func (e Employee) SayHi() {
	fmt.Printf(&quot;Hi, I am %s, I work at %s. Call me on %s\n&quot;, e.name, e.company, e.phone)
}

func main() {
	mike := Student{Human{&quot;mike&quot;, 25, &quot;11111111&quot;}, &quot;mit&quot;, 0.00}
	paul := Student{Human{&quot;paul&quot;, 20, &quot;12344553&quot;}, &quot;harvard&quot;, 1.22}
	sam := Employee{Human{&quot;sam&quot;, 30, &quot;11122333&quot;, }, &quot;things ltd.&quot;, 1000}
	tom := Employee{Human{&quot;tom&quot;, 40, &quot;12344555&quot;}, &quot;ws&quot;, 2000}

	// 定义Men
	var i Men

	i = mike
	fmt.Println(&quot;this is mike, a student:&quot;)
	i.SayHi()
	i.Sing(&quot;wo wo wo &quot;)

	i = tom
	fmt.Println(&quot;this is tom, a employee:&quot;)
	i.SayHi()
	i.Sing(&quot;o o o o&quot; )


	fmt.Println(&quot;let's use a slice of men and see what happens:&quot;)
	x := make([]Men, 3)
	x[0], x[1], x[2] = paul, sam, mike
	for _, value := range x {
		value.SayHi()
	}
}
</code></pre>

<h2 id="反射">反射</h2>

<p>Go语言实现了反射，所谓反射就是能检查程序在运行时的状态。我们一般用到的包是reflect包。如何运用reflect包，官方的这篇文章详细的讲解了reflect包的实现原理，<a href="http://golang.org/doc/articles/laws_of_reflection.html">laws of reflection</a></p>

<p><strong>一个例子:</strong></p>

<pre><code class="language-Go">package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

type User struct {
	Id int
	Name string
	Age int
}

func (u User) Hello() {
	fmt.Printf(&quot;Hello, wolrd.\n&quot;)
}

func Info(o interface{}) {
	t := reflect.TypeOf(o)
	fmt.Println(&quot;Type:&quot;, t.Name()) // 反射使用typeof和value of从接口中获取对象信息

	v := reflect.ValueOf(o)   // 打印出包含的字段
	fmt.Println(&quot;Fileds:&quot;)
	for i := 0; i &lt; t.NumField(); i++ {
		// t.NumField获取拥有的字段数量
		f := t.Field(i)
		val := v.Field(i).Interface()
		fmt.Printf(&quot;%6s:%v = %v\n&quot;, f.Name, f.Type, val)
	}

	for i := 0; i &lt; t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Printf(&quot;%6s:%v\n&quot;, m.Name, m.Type)
	}

}

func main() {
	u := User{1, &quot;Jack&quot;, 22}
	Info(u)
}
</code></pre>

<p><strong>结果:</strong></p>

<pre><code class="language-bash">Type: User
Fileds:
    Id:int = 1
  Name:string = Jack
   Age:int = 22
 Hello:func(main.User)
</code></pre>

<h2 id="goruntine-与-channels">Goruntine 与 channels</h2>

<p>goroutine是Go并行设计的核心。goroutine说到底其实就是协程，但是它比线程更小，十几个goroutine可能体现在底层就是五六个线程，Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB)，当然会根据相应的数据伸缩。也正因为如此，可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。</p>

<p>goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过<code>go</code>关键字实现了，其实就是一个普通的函数。</p>

<p>goroutine运行在相同的地址空间，因此访问共享内存必须做好同步。那么goroutine之间如何进行数据的通信呢，Go提供了一个很好的通信机制channel。channel可以与Unix shell 中的双向管道做类比：可以通过它发送或者接收值。这些值只能是特定的类型：channel类型。定义一个channel时，也需要定义发送到channel的值的类型。</p>

<p>go使用make 创建channel.</p>

<pre><code class="language-Go">
ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{})
</code></pre>

<p>channel通过操作符<code>&lt;-</code>来接收和发送数据</p>

<pre><code class="language-Go">
ch &lt;- v    // 发送v到channel ch.
v := &lt;-ch  // 从ch中接收数据，并赋值给v
</code></pre>

<p>上面我们介绍了默认的非缓存类型的channel，不过Go也允许指定channel的缓冲大小，很简单，就是channel可以存储多少元素。ch:= make(chan bool, 4)，创建了可以存储4个元素的bool 型channel。在这个channel 中，前4个元素可以无阻塞的写入。当写入第5个元素时，代码将会阻塞，直到其他goroutine从channel 中读取一些元素，腾出空间。</p>

<p>我们上面介绍的都是只有一个channel的情况，那么如果存在多个channel的时候，我们该如何操作呢，Go里面提供了一个关键字<code>select</code>，通过<code>select</code>可以监听channel上的数据流动。</p>

<p><code>select</code>默认是阻塞的，只有当监听的channel中有发送或接收可以进行时才会运行，当多个channel都准备好的时候，select是随机的选择一个执行的。</p>

<pre><code class="language-go">package main

import &quot;fmt&quot;

func fibonacci(c, quit chan int) {
	x, y := 1, 1

	for {
		select {
		case c &lt;- x:	// 将x放到c里, 当c空了的时候,即有取数据操作时
			x, y = y, x+y
		case &lt;-quit:	// 从 quit 里取数据, 当有数据放入 quit 里时
			fmt.Println(&quot;quit&quot;)
			return
		case &lt;- time.After(5 * time.Second):	// 超时
			println(&quot;timeout&quot;)
			break
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)

	go func() {
		for i := 0; i &lt; 10; i++ {
			fmt.Println(&lt;-c)
		}
		quit &lt;- 0
	}()

	fibonacci(c, quit)
}
</code></pre>

<h2 id="iota-枚举">iota 枚举</h2>

<p>用于在<code>const</code>中使用，初始为0，每次加一。</p>

<pre><code class="language-go">const (
  A = iota // 0
  B = iota // 1
  C = iota // 2
)
</code></pre>

<h2 id="defer">defer</h2>

<p>当函数执行到最后时，这些defer语句会按照逆序执行，最后该函数返回。如下代码所示，一般写打开一个资源是这样操作的：</p>

<pre><code class="language-Go">func ReadWrite() bool {
	file.Open(&quot;file&quot;)
	defer file.Close()
	if failureX {
		return false
	}
	if failureY {
		return false
	}
	return true
}
</code></pre>

<h2 id="array-slice-map">array,slice,map</h2>

<p><strong>数组</strong></p>

<p>声明方式如下：</p>

<pre><code class="language-go">var arr [n]type
</code></pre>

<p>注意：<code>[3]type</code>和<code>[4]type</code>是两种不同的类型。</p>

<p>其他声明方式：</p>

<pre><code class="language-go">a := [3]{1,2,3}
b := [10]{1,2,3}
c := [...]{1,2,3,4}     // 可以省略n，使用...标识，表示推断n
</code></pre>

<p><strong>切片</strong></p>

<p>切片是一种类似动态数组的数据类型。底层指向数组。声明与数组类似，只是不需要n。</p>

<pre><code class="language-go">var arr [n]int    // 数组
var sl []int      // 切片
</code></pre>

<blockquote>
<p>注意<code>slice</code>和数组在声明时的区别：声明数组时，方括号内写明了数组的长度或使用<code>...</code>自动计算长度，而声明<code>slice</code>时，方括号内没有任何字符。</p>
</blockquote>

<p>从概念上面来说<code>slice</code>像一个结构体，这个结构体包含了三个元素：</p>

<ul>
<li>一个指针，指向数组中<code>slice</code>指定的开始位置</li>
<li>长度，即<code>slice</code>的长度</li>
<li>最大长度，也就是<code>slice</code>开始位置到数组的最后位置的长度</li>
</ul>

<p><strong>map</strong></p>

<p>声明方式</p>

<pre><code class="language-go">var numbers map[string]int
// 另一种map的声明方式
numbers = make(map[string]int)
</code></pre>

<p>使用map过程中需要注意的几点：
- <code>map</code>是无序的，每次打印出来的<code>map</code>都会不一样，它不能通过<code>index</code>获取，而必须通过<code>key</code>获取
- <code>map</code>的长度是不固定的，也就是和<code>slice</code>一样，也是一种引用类型
- 内置的<code>len</code>函数同样适用于<code>map</code>，返回<code>map</code>拥有的<code>key</code>的数量
- <code>map</code>的值可以很方便的修改，通过<code>numbers[&quot;one&quot;]=11</code>可以很容易的把key为<code>one</code>的字典值改为<code>11</code>
- <code>map</code>和其他基本型别不同，它不是thread-safe，在多个go-routine存取时，必须使用mutex lock机制</p>

<h2 id="函数">函数</h2>

<p>函数是Go里面的核心设计，它通过关键字<code>func</code>来声明，它的格式如下：</p>

<pre><code class="language-Go">func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
	//这里是处理逻辑代码
	//返回多个值
	return value1, value2
}
</code></pre>

<p>上面的代码我们看出</p>

<ul>
<li>关键字<code>func</code>用来声明一个函数<code>funcName</code></li>
<li>函数可以有一个或者多个参数，每个参数后面带有类型，通过<code>,</code>分隔</li>
<li>函数可以返回多个值</li>
<li>上面返回值声明了两个变量<code>output1</code>和<code>output2</code>，如果你不想声明也可以，直接就两个类型</li>
<li>如果只有一个返回值且不声明返回值变量，那么你可以省略 包括返回值 的括号</li>
<li>如果没有返回值，那么就直接省略最后的返回信息</li>
<li>如果有返回值， 那么必须在函数的外层添加return语句</li>
</ul>

<h2 id="go-http包">Go Http包</h2>

<p>通过对http包的分析之后，现在让我们来梳理一下整个的代码执行过程。</p>

<ul>
<li><p>首先调用Http.HandleFunc</p>

<p>按顺序做了几件事：</p>

<p>1 调用了DefaultServeMux的HandleFunc</p>

<p>2 调用了DefaultServeMux的Handle</p>

<p>3 往DefaultServeMux的map[string]muxEntry中增加对应的handler和路由规则</p></li>

<li><p>其次调用http.ListenAndServe(&rdquo;:9090&rdquo;, nil)</p>

<p>按顺序做了几件事情：</p>

<p>1 实例化Server</p>

<p>2 调用Server的ListenAndServe()</p>

<p>3 调用net.Listen(&ldquo;tcp&rdquo;, addr)监听端口</p>

<p>4 启动一个for循环，在循环体中Accept请求</p>

<p>5 对每个请求实例化一个Conn，并且开启一个goroutine为这个请求进行服务go c.serve()</p>

<p>6 读取每个请求的内容w, err := c.readRequest()</p>

<p>7 判断handler是否为空，如果没有设置handler（这个例子就没有设置handler），handler就设置为DefaultServeMux</p>

<p>8 调用handler的ServeHttp</p>

<p>9 在这个例子中，下面就进入到DefaultServeMux.ServeHttp</p>

<p>10 根据request选择handler，并且进入到这个handler的ServeHTTP</p>

<pre><code>mux.handler(r).ServeHTTP(w, r)
</code></pre>

<p>11 选择handler：</p>

<p>A 判断是否有路由能满足这个request（循环遍历ServeMux的muxEntry）</p>

<p>B 如果有路由满足，调用这个路由handler的ServeHTTP</p>

<p>C 如果没有路由满足，调用NotFoundHandler的ServeHTTP</p></li>
</ul>

<hr />

<p>a tutorial learn from <a href="https://golangbot.com">https://golangbot.com</a></p>

<h2 id="type">type</h2>

<p>the basic types available in go :</p>

<ul>
<li>bool</li>
<li>Numeric Types

<ul>
<li>int8/uint8, int16/uint16, int32/uint32, int64/uint64, int/uint</li>
<li>float32, float64</li>
<li>complex64, complex128</li>
<li>byte</li>
<li>rune</li>
</ul></li>
<li>string</li>
</ul>

<p>int: represents 32 or 64 bit integers depending on the underlying platform. You should generally be using int to represent integers unless there is a need to use a specific sized integer.</p>

<p>The type of a variable can be printed using %T format specifier in Printf method.</p>

<pre><code class="language-go">package main

import (  
    &quot;fmt&quot;
)

func main() {  
    const a = 5
    var intVar int = a
    var int32Var int32 = a
    var float64Var float64 = a
    var complex64Var complex64 = a
    fmt.Println(&quot;intVar&quot;,intVar, &quot;\nint32Var&quot;, int32Var, &quot;\nfloat64Var&quot;, float64Var, &quot;\ncomplex64Var&quot;,complex64Var)
}
// In this program, the value of a is 5 and the syntax of a is generic 
// (it can represent a float, integer or even a complex number with no imaginary part) 
// and hence it is possible to be assigned to any compatible type. 

</code></pre>

<h2 id="function">function</h2>

<p>A function is a block of code that performs a specific task. A function takes a input, performs some calculations on the input and generates a output.</p>

<pre><code class="language-go">func rectProps(length, width float64)(area, perimeter float64) {  
    area = length * width
    perimeter = (length + width) * 2
    return //no explicit return value
}
// it's ok
</code></pre>

<h2 id="package">package</h2>

<p>The order of initialisation of a package is as follows</p>

<ol>
<li>Package level variables are initialised first</li>
<li>init function is called next. A package can have multiple init functions (either in a single file or distributed across multiple files) and they are called in the order in which they are presented to the compiler.</li>
</ol>

<p>If a package imports other packages, the imported packages are initialised first.</p>

<p>It is possible to include multiple expressions in a case by separating them with comma.</p>

<h2 id="if-loop-switch">if loop switch</h2>

<p>The expression in a switch is optional and it can be omitted. If the expression is omitted, the switch is considered to be switch true and each of the case expression is evaluated for truth and the corresponding block of code is executed.</p>

<p>In Go the control comes out of the switch statement immediately after a case is executed. A fallthrough statement is used to transfer control to the first statement of the case that is present immediately after the case which has been executed.</p>

<h2 id="array">array</h2>

<p>An array belongs to type n[T]. n denotes the number of elements in an array and T represents the type of each element. The number of elements n is also a part of the type</p>

<p>The size of the array is a part of the type. Hence [5]int and [25]int are distinct types. Because of this, arrays cannot be resized. Don&rsquo;t worry about this restriction since slices exist to overcome this.</p>

<p>Arrays in Go are value types and not reference types.</p>

<p>Go provides a better and concise way to iterate over an array by using the range form of the for loop. range returns both the index and the value at that index.</p>

<h2 id="slice">slice</h2>

<p>A slice is a convenient, flexible and powerful wrapper on top of an array. Slices do not own any data on their own. They are the just references to existing arrays.</p>

<p>A slice with elements of type T is represented by []T</p>

<p>The length of the slice is the number of elements in the slice. The capacity of the slice is the number of elements in the underlying array starting from the index from which the slice is created.</p>

<p>func make([]T, len, cap) []T can be used to create a slice by passing the type, length and capacity. The capacity parameter is optional and defaults to the length. The make function creates an array and returns a slice reference to it.</p>

<p>Slices hold a reference to the underlying array. As long as the slice is in memory, the array cannot be garbage collected. This might be of concern when it comes to memory management. Lets assume that we have a very large array and we are interested in processing only a small part of it. Henceforth we create a slice from that array and start processing the slice. The important thing to be noted here is that the array will still be in memory since the slice references it.</p>

<p>One way to solve this problem is to use the copy function func copy(dst, src []T) int to make a copy of that slice. This way we can use the new slice and the original array can be garbage collected.</p>

<p>A variadic function is a function that can accept variable number of arguments. the last paramter is a type of slice. in fucntion , we can get the element by range form, for example :</p>

<pre><code class="language-go">func variadic(name string, peoples ... string) string {
	for people , _ := range peoples {
		fmt.Println(people)
		if people == name {
			fmt.Println(&quot;get it&quot;)
		}
	}
}

</code></pre>

<p>The way variadic functions work is by converting the variable number of arguments passed, to a new slice of the type of the variadic parameter.</p>

<h2 id="map">map</h2>

<p>Similar to slices, maps are reference types. When a map is assigned to a new variable, they both point to the same internal data structure. Hence changes made in one will reflect in the other.</p>

<p>Similar to slices, maps are reference types. When a map is assigned to a new variable, they both point to the same internal data structure. Hence changes made in one will reflect in the other.</p>

<h2 id="string">string</h2>

<p>Since a string is a slice of bytes, it&rsquo;s possible to access each byte of a string.</p>

<p>A rune is a builtin type in Go and it&rsquo;s the alias of int32. rune represents a Unicode code point in Go. It does not matter how many bytes the code point occupies, it can be represented by a rune.</p>

<pre><code class="language-go">
func PrintChar1(str string) {
	lens := len(str)
	for i := 0; i&lt;lens; i++ {
		fmt.Printf(&quot;%c&quot;, str[i])
	}
}

func PrintChar2(str string) {
	runes := []rune(str)
	for i := 0; i&lt;len(runes); i++ {
		fmt.Println(&quot;%c&quot;, runes[i])
	}
}

</code></pre>

<p>Strings are immutable in Go. Once a string is created it&rsquo;s not possible to change it. (why, string is a slice ???)</p>

<p>strings are converted to a slice of runes. Then that slice is mutated with whatever changes needed and converted back to a new string.</p>

<h2 id="point">point</h2>

<p>Go does not support pointer arithmetic which is present in other languages like C.</p>

<h2 id="struct">struct</h2>

<p>A structure is a user defined type which represents a collection of fields.</p>

<p>two types : named structures and anonymous structures.</p>

<p>It is possible to create structs with fields which contain only a type without the field name. These kind of fields are called anonymous fields.</p>

<p>It is possible to create structs with fields which contain only a type without the field name. These kind of fields are called anonymous fields.</p>

<p>Fields that belong to a anonymous struct field in a structure are called <em>promoted fields</em> since they can be accessed as if they belong to the structure which holds the anonymous struct field.</p>

<pre><code class="language-go">type Address {
	city string
	state int
}

type Person {
	name string
	age int
	Address
}

// we can use Person like this :
ots := Person{
	name: 	'ots'
	age:	28
	Address: Address {
		city:	'js'
		state: 	23
	}xs
}

var city string = ots.city

</code></pre>

<p>Structs are value types and are comparable if each of their fields are comparable. Two struct variables are considered equal if their corresponding fields are equal.</p>

<h2 id="methods">Methods</h2>

<p>There are a couple of reasons for methods. Lets look at them one by one.</p>

<ul>
<li><p>Go is not a pure object oriented programming language and it does not support classes. Hence methods on types is a way to achieve behaviour similar to classes.</p></li>

<li><p>Methods with same name can be defined on different types whereas functions with the same names are not allowed.</p></li>
</ul>

<p><em>Methods belonging to anonymous fields of a struct can be called as if they belong to the structure where the anonymous field is defined.</em></p>

<p><em>differents of function argument and method receiver</em></p>

<ul>
<li>When a function has a value argument, it will accept only a value argument.</li>
<li>When a method has a value receiver, it will accept both pointer and value receivers.</li>
</ul>

<h2 id="concurrency">concurrency</h2>

<p>Concurrency is the capability to deal with lots of things at once.</p>

<p>Parallelism is doing lots of things at the same time. It might sound similar to concurrency but it&rsquo;s actually different.</p>

<p>concurrency is dealing the different things at once, may not the same time, one by one, then, different thing may look like beding dealing at the same time .  think about joging and listening music, this is parallelim, and joging with tying shoe laces are concurrency.</p>

<p>We can solve the race condition problem using both mutexes and channels.</p>

<p>In general use channels when Goroutines need to communicate with each other and mutexes when only one Goroutine should access the critical section of code.</p>

<h2 id="oop-in-go">OOP in Go</h2>

<p>it is not possible to anonymously embed a slice. A field name is required.</p>

<p>Any type which defines all the methods of an interface is said to implicitly implement that interface.</p>

<p>A variable of type interface can hold any value which implements the interface. This property of interfaces is used to achieve polymorphism in Go.</p>

<h2 id="defer-and-error-handling-and-panic">DEFER and Error Handling and Panic</h2>

<p>Defer statement is used to execute a function call just before the function where the defer statement is present returns.</p>

<p>If a function or method returns an error, then by convention it has to be the last value returned from the function. Hence the Open function returns err as the last value.</p>

<p>The idiomatic way of handling error in Go is to compare the returned error to nil. A nil value indicates that no error has occurred and a non nil value indicates the presence of an error.</p>

<p>the define of error type:</p>

<pre><code class="language-go">type error interface {
	Error() string
}
</code></pre>

<p>One important factor is that you should avoid panic and recover and use errors where ever possible. Only in cases where the program just cannot continue execution should a panic and recover mechanism be used.</p>

<p>When a function encounters a panic, its execution is stopped, any deferred functions are executed and then the control returns to its caller. This process continues until all the functions of the current goroutine have returned at which point the program prints the panic message, followed by the stack trace and then terminates.</p>

<p>recover is a builtin function which is used to regain control of a panicking goroutine. Recover is useful only when called inside deferred functions.</p>

<pre><code class="language-go">// a example of Recover

package main

import (  
    &quot;fmt&quot;
)

func recoverName() {  
	// define a recover 
    if r := recover(); r!= nil {
        fmt.Println(&quot;recovered from &quot;, r)
    }
}

func fullName(firstName *string, lastName *string) {  
    defer recoverName()
    if firstName == nil {
        panic(&quot;runtime error: first name cannot be nil&quot;)
    }
    if lastName == nil {
        panic(&quot;runtime error: last name cannot be nil&quot;)
    }
    fmt.Printf(&quot;%s %s\n&quot;, *firstName, *lastName)
    fmt.Println(&quot;returned normally from fullName&quot;)
}

func main() {  
    defer fmt.Println(&quot;deferred call in main&quot;)
    firstName := &quot;Elon&quot;
    fullName(&amp;firstName, nil)
    fmt.Println(&quot;returned normally from main&quot;)
}
</code></pre>

<p>Recover works only when it is called from the same goroutine. It&rsquo;s not possible to recover from a panic that has happened in a different goroutine.</p>

<h2 id="first-class-function">First class function</h2>

<p>A language which supports first class functions allows functions to be assigned to variables, passed as arguments to other functions and returned from other functions. Go has support for first class functions.</p>

<p>The definition of Higher-order function from wiki is a function which does at least one of the following</p>

<ul>
<li>takes one or more functions as arguments</li>
<li>returns a function as its result</li>
</ul>

<p>Closures are a special case of anonymous functions. Closures are anonymous functions which access the variables defined outside the body of the function.</p>

<p>Every closure is bound to its own surrounding variable.</p>

<h2 id="file">File</h2>

<pre><code class="language-go">
import (
	&quot;io/ioutil&quot;
	&quot;bufio&quot;
	&quot;fmt&quot;
)

// 功能性代码，不能运行
func FileInTest() {
	var fileName = &quot;xxx.txt&quot;

	data, err := ioutil.ReadFile(fileName)

	f, err := os.Open(fileName)
	r := bufio.NewReader(f)

	b := make([]byte, 8)
	_, err := r.Read(b)

	s := bufio.NewScanner(f)
	for s.Sacn() {
		fmt.Println(s.Text())
	}
}

</code></pre>

<p>``` go
import (
    &ldquo;fmt&rdquo;
    &ldquo;os&rdquo;
)</p>

<p>func FileOutTest () {
    f, err := os.Create(&ldquo;test.txt&rdquo;)</p>

<pre><code>l, err := f.WriteString(&quot;sssss&quot;)

// ...
f.Close()

// byte
d := []byte{1,2,3,4}

l, err := f.Write(d)

// line by line
v := &quot;xxxxx&quot;
fmt.Fprintln(f, v)

// append
f, err := os.OpenFile(&quot;lines&quot;, os.O_APPEND|os.O_WRONLY, 0644)
</code></pre>

<p>}</p>
                        </div>

                        


                        


                        <div class="post-meta meta-tags">
                            
                            <ul class="clearfix">
                                
                                <li><a href="https://otswang.gitee.io/hugo/tags/go">Go</a></li>
                                
                            </ul>
                            
                        </div>
                    </article>
                    
    

    
    
                </div>
            </div>
            <div id="secondary">

    <section class="widget">
        <form id="search" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://otswang.gitee.io/hugo/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>

    
    <div class="clear">
        <div class="toc-article">
            <div class="toc-title">文章目录</dixsv>
            <nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#go-哲学">Go 哲学</a></li>
<li><a href="#概览">概览</a></li>
<li><a href="#数据类型">数据类型</a></li>
<li><a href="#可见性">可见性</a></li>
<li><a href="#定义变量">定义变量</a></li>
<li><a href="#语法规则">语法规则</a></li>
<li><a href="#go的包-package">Go的包 package</a></li>
<li><a href="#go的-make-与-new">Go的 make 与 new</a></li>
<li><a href="#panic和recover">Panic和Recover</a></li>
<li><a href="#main-函数和-init-函数"><code>main</code>函数和<code>init</code>函数</a></li>
<li><a href="#method">method</a></li>
<li><a href="#interface">interface</a></li>
<li><a href="#反射">反射</a></li>
<li><a href="#goruntine-与-channels">Goruntine 与 channels</a></li>
<li><a href="#iota-枚举">iota 枚举</a></li>
<li><a href="#defer">defer</a></li>
<li><a href="#array-slice-map">array,slice,map</a></li>
<li><a href="#函数">函数</a></li>
<li><a href="#go-http包">Go Http包</a></li>
<li><a href="#type">type</a></li>
<li><a href="#function">function</a></li>
<li><a href="#package">package</a></li>
<li><a href="#if-loop-switch">if loop switch</a></li>
<li><a href="#array">array</a></li>
<li><a href="#slice">slice</a></li>
<li><a href="#map">map</a></li>
<li><a href="#string">string</a></li>
<li><a href="#point">point</a></li>
<li><a href="#struct">struct</a></li>
<li><a href="#methods">Methods</a></li>
<li><a href="#concurrency">concurrency</a></li>
<li><a href="#oop-in-go">OOP in Go</a></li>
<li><a href="#defer-and-error-handling-and-panic">DEFER and Error Handling and Panic</a></li>
<li><a href="#first-class-function">First class function</a></li>
<li><a href="#file">File</a></li>
</ul></li>
</ul>
</nav>
        </div>
    </div>
    

</div>
        </div>
    </div>
</div>
<footer id="footer">
    <div class="container">
        &copy; 2020 <a href="https://otswang.gitee.io/hugo/">The Sky of OtsWang By OtsWang</a>.
        Powered by <a rel="nofollow noreferer noopener" href="https://gohugo.io" target="_blank">Hugo</a>.
        <a href="https://www.flysnow.org/" target="_blank">Theme</a> based on <a href="https://github.com/Dudiao137/maupassant-hugo" target="_blank">maupassant-ots</a>.
        
    </div>
</footer>


    <script type="text/javascript">
    
    (function(){
        $("pre code").parent().addClass("line-numbers")
    }())

    window.MathJax = {
        tex2jax: {
            inlineMath: [ ['$','$'] ],
            processEscapes: true
        }
    };
    </script>
    <script type="text/javascript" src="/hugo/js/prism.js" async="true"></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src="/hugo/js/totop.js?v=0.0.0" async=""></script>







 
 <script src="https://mermaidjs.github.io/scripts/mermaid.min.js"></script>
 <script>
       mermaid.initialize({ startOnLoad: true });
 </script>
</body>
</html>
